// kernel/test_mem.c
#include "riscv.h"
#include "types.h"
#include "param.h"
#include "memlayout.h"
#include "mmu.h"
#include "test_mem.h"

void test_physical_memory(void)
{
    cprintf("=== Testing Physical Memory Manager ===\n");
    
    pmm_stats();
    
    // 测试基本分配
    void *page1 = alloc_page();
    void *page2 = alloc_page();
    
    if(page1 == 0 || page2 == 0) {
        panic("test_physical_memory: alloc_page failed");
    }
    
    if(page1 == page2) {
        panic("test_physical_memory: duplicate page allocation");
    }
    
    // 测试页对齐
    if((uint64)page1 % PAGE_SIZE != 0 || (uint64)page2 % PAGE_SIZE != 0) {
        panic("test_physical_memory: page not aligned");
    }
    
    // 测试数据读写
    *(uint64*)page1 = 0x123456789ABCDEF0;
    if(*(uint64*)page1 != 0x123456789ABCDEF0) {
        panic("test_physical_memory: data write failed");
    }
    
    // 测试释放和重新分配
    free_page(page1);
    void *page3 = alloc_page();
    
    pmm_stats();
    cprintf("Physical memory test passed!\n");
}

void test_pagetable(void)
{
    cprintf("=== Testing Page Table Manager ===\n");
    
    pagetable_t pt = create_pagetable();
    if(pt == 0) {
        panic("test_pagetable: create_pagetable failed");
    }
    
    // 测试映射
    uint64 va = 0x1000000; // 测试虚拟地址
    uint64 pa = (uint64)alloc_page();
    
    if(map_page(pt, va, pa, PTE_R | PTE_W) < 0) {
        panic("test_pagetable: map_page failed");
    }
    
    // 测试地址转换
    pte_t *pte = walk_lookup(pt, va);
    if(pte == 0 || !(*pte & PTE_V)) {
        panic("test_pagetable: walk_lookup failed");
    }
    
    if(PTE2PA(*pte) != pa) {
        panic("test_pagetable: address translation failed");
    }
    
    // 测试权限位
    if(!(*pte & PTE_R) || !(*pte & PTE_W)) {
        panic("test_pagetable: permission bits incorrect");
    }
    
    // 测试数据访问
    *(uint64*)va = 0xDEADBEEF;
    if(*(uint64*)va != 0xDEADBEEF) {
        panic("test_pagetable: data access through page table failed");
    }
    
    cprintf("Page table contents:\n");
    dump_pagetable(pt, 2);
    
    free_pagetable(pt, 2);
    cprintf("Page table test passed!\n");
}

void test_virtual_memory(void)
{
    cprintf("=== Testing Virtual Memory ===\n");
    
    // 保存当前satp
    uint64 old_satp = r_satp();
    
    // 初始化并启用内核页表
    kvminit();
    kvminithart();
    
    // 测试内核功能仍然正常
    printf("Kernel is still alive after enabling paging!\n");
    
    // 测试UART访问（通过设备映射）
    volatile uint32 *uart = (uint32*)UART0;
    uint32 uart_value = uart[0]; // 读取UART寄存器
    
    printf("UART access through virtual memory: 0x%x\n", uart_value);
    
    // 恢复原页表（如果需要）
    // w_satp(old_satp);
    // sfence_vma();
    
    printf("Virtual memory test passed!\n");
}